#pragma once

#include <iostream>
#include <cstdio>
#include <vector>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include "Task.hpp"

#define CHILD_PROCESS_NUM 3
#define ERR_EXIT(m)         \
    do                      \
    {                       \
        perror(m);          \
        exit(EXIT_FAILURE); \
    } while (0)

class Channel // 子进程的pid，父进程对应该子进程的匿名管道的写端
{
public:
    Channel(pid_t chpid, int wfd)
        : _chpid(chpid), _wfd(wfd)
    {
    }

    pid_t getpid()
    {
        return _chpid;
    }

    int getwfd()
    {
        return _wfd;
    }

    void Close()
    {
        close(_wfd);
    }

    void Wait()
    {
        waitpid(_chpid,nullptr,0);
    }

private:
    pid_t _chpid;
    int _wfd;
};

class ChannelManager
{
public:
    void InsertChannel(pid_t pid, int wfd)
    {
        channels.emplace_back(pid, wfd);
    }

    int wfd(int index)
    {
        return channels[index % channels.size()].getwfd();
    }

    int pid(int index)
    {
        return channels[index % channels.size()].getpid();
    }

    void Printf()
    {
        for (auto e : channels)
            printf("child pid : %d , wfd : %d\n", e.getpid(), e.getwfd());
    }

    void Close()
    {
        for (auto e : channels)
            e.Close();
    }
    
    void Wait()
    {
        for (auto e : channels)
            e.Wait();
    }

private:
    std::vector<Channel> channels;
};

class ProcessPool
{
public:
    ProcessPool(int num)
        : _child_process_num(num)
    {
        _tm.RegisterTask(func1);
        _tm.RegisterTask(func2);
        _tm.RegisterTask(func3);
    }

    void Work(int rfd)
    {
        while (true)
        {
            int code = 0;
            int n = read(rfd, &code, sizeof(int));
            if (n == 0)
                break;
            else if (n == 4)
            {
                _tm.ExecuteTask(code);
            }
            else
            {
                continue;
            }
        }
    }

    void Create()
    {
        for (int i = 0; i < _child_process_num; ++i)
        {
            int fds[2] = {0};
            int n = pipe(fds);
            if (n != 0)
                ERR_EXIT("pipe");

            int pid = fork();
            if (pid == -1)
                ERR_EXIT("fork");
            else if (pid == 0)
            {
                // child
                close(fds[1]); // 关闭自己的写端
                _cm.Close(); // 关闭哥哥进程的写端

                Work(fds[0]);

                close(fds[0]);
                exit(0);
            }
            else
            {
                // parent
                close(fds[0]);
                _cm.InsertChannel(pid, fds[1]);
            }
        }
        std::cout << "Create Success" << std::endl;
        _cm.Printf();
    }

    void Run()
    {
        int i = 0;
        while (true)
        {
            sleep(1);

            int code = _tm.Code();
            std::cout << "发送child " << _cm.pid(i) << " 一个任务码" << code << std::endl;
            write(_cm.wfd(i), &code, sizeof(int));

            i++;
        }
    }

    ~ProcessPool()
    {
        // 关闭父进程的写端即可，子进程都读到结尾，退出。
        _cm.Close();
        // 回收子进程。
        _cm.Wait();
    }

private:
    int _child_process_num;
    ChannelManager _cm;
    TaskManager _tm;
};
